#include <queue>
#include <string>
#include <pthread.h>
using std::queue;
using std::string;

static const int defaultCap = 5;

namespace Yohifo
{
    template<class T>
    class BlockQueue
    {
    public:
        BlockQueue(int cap = defaultCap) :_cap(cap)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cCond, nullptr);
            pthread_cond_init(&_pCond, nullptr);
        }

        ~BlockQueue()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cCond);
            pthread_cond_destroy(&_pCond);
        }

        void push(const T &in)
        {
            //上锁互斥
            pthread_mutex_lock(&_mutex);

            while(isFull()) pthread_cond_wait(&_pCond, &_mutex);

            //此时队列有空间
            _q.push(in);

            pthread_cond_signal(&_cCond);   //需要唤醒消费者继续消费
            pthread_mutex_unlock(&_mutex);
        }

        void pop(T &out)
        {
            //加锁互斥
            pthread_mutex_lock(&_mutex);

            while(isEmpty()) pthread_cond_wait(&_cCond, &_mutex);

            out = _q.front();
            _q.pop();

            pthread_cond_signal(&_pCond);   //需要唤醒生产者继续生产
            pthread_mutex_unlock(&_mutex);
        }

    private:
        bool isFull() const { return _q.size() == _cap; }
        bool isEmpty() const { return _q.empty(); }

    private:
        queue<T> _q;    //队列
        int _cap;   //容量
        pthread_mutex_t _mutex; //互斥锁
        pthread_cond_t _cCond;  //消费者条件变量
        pthread_cond_t _pCond;  //生产者条件变量
    };

    template<class T>
    class Info
    {
    public:
        Info(BlockQueue<T>* pq = nullptr, string &&name = string(), pthread_t id = 0)
            :_id(id)
            ,_pq(pq)
        {
            _name.swap(name);
        }

    public:
        BlockQueue<T>* _pq;
        string _name;
        pthread_t _id;
    };
}